package br.edu.ufcg.splab.io;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import br.edu.ufcg.splab.core.InterfaceVertex;
import br.edu.ufcg.splab.core.graph.Graph;
import br.edu.ufcg.splab.exceptions.ParseException;



public class RecursiveTGFParser {
	
	public Graph parseTGF(String fileName) throws ParseException{
		List<String> lines = this.getLines(fileName);
		int hashLineIndex = this.hashLineIndex(lines);
		if(hashLineIndex == -1){
			throw new ParseException("The TGF file must have a \"#\" separating the nodes and edges definition.");
		}else if(hashLineIndex == 0){
			throw new ParseException("The TGF file must define at least one node.");
		}
		Graph graph = new Graph();
		int currentLineIndex = 0;
		String currentLine = "";
		while(currentLineIndex < lines.size() && !currentLine.equals("#")){ //node declarations. It executes while the "#" doesn't appear
			currentLine = lines.get(currentLineIndex);
			currentLineIndex++;
			String[] tokens = currentLine.split("\\s");
			if(tokens.length != 2){
				throw new ParseException("Line " + (currentLine) + ": The node definition line must contain exactly two fields.");
			}
			String firstLabel = tokens[0].trim();
			String secondLabel = tokens[1].trim();
			if(!isInteger(firstLabel) || !isInteger(secondLabel)){
				throw new ParseException("Line " + (currentLine) + ": The " + (isInteger(firstLabel) ? "first": "second") + " field must be an integer number.");
			}
			if(!firstLabel.equals(secondLabel)){
				throw new ParseException("Line " + (currentLine) + ": The two labels must be equal.");
			}
			if(this.getVertex(graph, firstLabel) != null){
				throw new ParseException("Line " + (currentLine) + ": Duplicated node.");
			}
			graph.addVertex(firstLabel);
		}
		
		while(currentLineIndex < lines.size()){
			currentLineIndex++;
			currentLine = lines.get(currentLineIndex);
			String[] tokens = currentLine.split("\\s");
			if(tokens.length < 3){
				throw new ParseException("Line " + (currentLine) + ": The edge definition line must contain more than two fields.");
			}
			String firstLabel = tokens[0].trim();
			String secondLabel = tokens[1].trim();
			if(!isInteger(firstLabel) || !isInteger(secondLabel)){
				throw new ParseException("Line " + (currentLine) + ": The " + (isInteger(firstLabel) ? "first": "second") + " field must be an integer number.");
			}
			String thirdLabel = this.gatherLabels(tokens);
		}
		return graph;
	}
	
	private String gatherLabels(String[] tokens) {
		String label = "";
		for (int i = 2; i < tokens.length; i++) {
			label += tokens[i];
			if(i != tokens.length - 1){
				label += " ";
			}
		}
		return label;
	}

	private int hashLineIndex(List<String> lines) {
		for (int i = 0; i < lines.size(); i++) {
			String line = lines.get(i);
			if(line.trim().equals("#")){
				return i;
			}
		}
		return -1;
	}

	private List<String> getLines(String fileName) throws ParseException{
		List<String> lines = new ArrayList<String>();
		try {
			Scanner scanner = new Scanner(new File(fileName));
			while(scanner.hasNextLine()){
				lines.add(scanner.nextLine());
			}
			scanner.close();
			return lines;
		} catch (FileNotFoundException e) {
			throw new ParseException("The input file does not exist.");
		}
	}
	
	private boolean isInteger(String numberRepresentation){
		try{
			Integer.parseInt(numberRepresentation);
			return true;
		}catch(NumberFormatException exception){
			return false;
		}
	}
	
	private InterfaceVertex getVertex(Graph graph, String label){
		for (InterfaceVertex vertex: graph.getStates().values()) {
			if(vertex.getLabel().equals(label)){
				return vertex;
			}
		}
		return null;
	}
	
}
